// 作用：Webpack打包的入口文件

// 导入 Vue 构造函数
import Vue from 'vue'

// 导入第三方重置样式模块
import 'normalize.css/normalize.css'

// 导入 ElementUI 整个组件
import ElementUI from 'element-ui'
// 导入 ElementUI 整个组件的样式
import 'element-ui/lib/theme-chalk/index.css'
// 导入 ElementUI 的英文语言包
import elementEN from 'element-ui/lib/locale/lang/en'
// 导入 ElementUI 的中文语言包
import elementZH from 'element-ui/lib/locale/lang/zh-CN'

// 导入 自己的 的英文语言包
import customEN from './lang/en'
// 导入 自己的 的中文语言包
import customZH from './lang/zh'

// 导入自己的样式文件
import '@/styles/index.scss' // global css

// 导入项目根组件
import App from './App'
// 导入 store 实例
import store from './store'
// 导入 router 实例
import router from './router'

// 导入字体图标
import '@/icons'
// 导入权限控制文件
import '@/permission'
// 导入自定义指令模块
import '@/directive'

// import arr, { obj, fn } from '../test/a'
// console.log(arr)
// console.log(obj)
// fn()
// 从某个模块下导入所有的成员赋值给obj变量
// import * as obj from '../test/a'
// console.log(obj)
// 获取默认导出的成员：
// console.log(obj.default)// [1, 2, 3]
// 获取按需默认导出的成员：
// console.log(obj.obj)//
// obj.fn()

// 打印模块
import VuePrint from 'vue-print-nb'
// 注册 -> 提供全局的v-print指令
Vue.use(VuePrint)

// 导入全局组件
import PageHeader from '@/components/PageHeader'
import UploadExcel from '@/components/UploadExcel'
import UploadImg from '@/components/UploadImg'
import ThemePicker from '@/components/ThemePicker'
// import ScreenFull from '@/components/ScreenFull'
import Lang from '@/components/Lang'
import TagsView from '@/components/TagsView'
// 注册全局组件
Vue.component(PageHeader.name, PageHeader)
Vue.component(UploadExcel.name, UploadExcel)
Vue.component(UploadImg.name, UploadImg)
Vue.component(UploadImg.name, UploadImg)
// Vue.component(ScreenFull.name, ScreenFull)
Vue.component(ThemePicker.name, ThemePicker)
Vue.component(Lang.name, Lang)
Vue.component(TagsView.name, TagsView)

Vue.prototype.$checkPermission = function (key) {
  // 拿到vuex中points数组
  const { points } = store.state.user.userInfo.roles
  // 判断当前传入的权限点在不在points
  return points.includes(key)
}

// 注册 ElementUI 的全部组件，并提供英文语言模式
// Vue.use(ElementUI, { locale })
// 如果想要中文版 element-ui，按如下方式声明
Vue.use(ElementUI)

Vue.config.productionTip = false

// 多语言切换(国际化)
// 1. 下包：yarn add vue-i18n@8 -S
// 2. 引入
import VueI18n from 'vue-i18n'
// 3. 注册
Vue.use(VueI18n)
// 4. 定义翻译规则 = ElementUI+自己的
const messages = {
  // 英文
  en: {
    // 对象展开到新对象中
    ...elementEN,
    ...customEN
  },
  // 中文
  zh: {
    // 对象展开到新对象中
    ...elementZH,
    ...customZH
  }
}
import Cookies from 'js-cookie'
// 5. 创建i18n实例
const i18n = new VueI18n({
  // 刷新页面的时候取出Cookie的值
  locale: Cookies.get('language') || 'zh', // 默认的语言，zh表示中文
  messages// 翻译的规则
})
// 6. 注入

// 实例化 vm 实例
new Vue({
  // 注入 router 实例
  router,
  // 注入 store 实例
  store,
  // 注入 i18n 实例
  i18n, // 提供全局的 $t 方法，进行语言的翻译
  // 渲染函数，把根组件App的内容渲染到id=app的盒子位置
  // id=app盒子在public/index.html文件中
  render: h => h(App)
}).$mount('#app')

// nvm切换node版本：
// 1. 全局安装nvm: npm i nvm -g
// 2. 查看所有node版本: nvm ls
// 3. 切换node版本: nvm use 指定node版本号
// 4. 查看node版本: node -v

// 什么是虚拟DOM为啥用虚拟DOM？
// 1. 概念: 保存了DOM元素关键信息的一个JS对象
// 2. 好处: 大大减少比对的次数、大大提高DOM更新的速度

// 什么diff算法及有啥用diff算法？
// 1. 概念: 找不同算法
// 2. diff算法: 在Vue中当数据变了，比对数据变化前后两份虚拟DOM的差异，
//              找到虚拟DOM变化的地方，然后把对应的差异映射到真实DOM

// 闭包的概念优缺点：
// 概念：两个函数嵌套，内函数用到了外函数的变量，
//      导致外函数的变量不会被释放，延长了外函数变量的生命周期
// 优点：让变量私有化(局部变量)，对外提供访问方法
// 缺点/特点：内存泄露

// function f () {
//   let a = 0
//   return function () {
//     a++
//     console.log(a)
//   }
// }
// const fn = f()
// fn()
// 一段函数递归代码，给出输出结果
// function f (a) {
//   if (a >= 1) {
//     console.log(a)// 5 4 3 2 1
//     f(--a)//
//   }
//   console.log(a)// 0 0 1 2 3 4
// }
// f(5)

// 字符串的 substr、substring、slice 3个方法
// 作用：字符串的截取(提取)
// const str = 'Love'
// console.log(str.substr(2))
// console.log(str.substring(2))
// console.log(str.slice(2))

// 数据源（对象数组）
// const arr = [
//   {
//     name: 'aaa',
//     str1: '姬霓'
//   }, {
//     name: 'bbb',
//     str1: '小黑'
//   }, {
//     name: 'aaa',
//     str2: '太美'
//   }, {
//     name: 'bbb',
//     str2: '子'
//   }
// ]
// // 需求：把name属性相同的对象做合并，最终得到一个数组
// // 声明空数组
// const list = []
// // 遍历 arr 数组
// arr.forEach((item) => {
//   // 判断list中是否存在item.name属性
//   const i = list.findIndex(obj => obj.name === item.name)
//   // 如果下标不等于-1，说明item中不存在item
//   if (i === -1) {
//     // 直接push到list数组中
//     list.push(item)
//   } else {
//     // 否则，说明item中存在item
//     // 把list中的对象取出来，再和item做个对象合并，最后再赋值会list中
//     list[i] = {
//       ...list[i],
//       ...item
//     }
//   }
// })
// // 打印结果测试
// // console.log(list)

// const obj1 = {
//   '入职日期': 44266,
//   '姓名': '宋轶',
//   '工号': 88088,
//   '手机号': 15751786628,
//   '转正日期': 44450
// }
// const zh2EnKey = {
//   '入职日期': 'timeOfEntry',
//   '姓名': 'username',
//   '工号': 'workNumber',
//   '手机号': 'mobile',
//   '转正日期': 'correctionTime'
// }
// // 遍历obj1对象，拿到每个中文key对应英文key
// const item = {
// }
// Object.keys(obj1).forEach(key => {
//   // key: 中文key
//   // 得到英文key
//   const enKey = zh2EnKey[key]
//   // 给item动态新增enKey属性，赋值
//   item[enKey] = obj1[key]
// })
// console.log(item)
// // const obj2 = {
// //   timeOfEntry: 44266,
// //   username: '宋轶',
// //   workNumber: 88088,
// //   mobile: 15751786628,
// //   correctionTime: 44450
// // }

const header = ['姓名', '部门', '手机号', '工号', '聘用形式', '入职日期', '转正日期']
const obj1 = {
  correctionTime: '2018-11-30',
  formOfEmployment: '1',
  workNumber: '9002',
  mobile: '13800000002',
  username: '肖威',
  departmentName: '总裁办',
  timeOfEntry: '2018-11-02'
}
const headerRalation = {
  '手机号': 'mobile',
  '姓名': 'username',
  '聘用形式': 'formOfEmployment',
  '入职日期': 'timeOfEntry',
  '工号': 'workNumber',
  '转正日期': 'correctionTime',
  '部门': 'departmentName'
}
// ['肖威', '总裁办', '13800000002', '9002', '1', '2018-11-02', '2018-11-30']
const arr = []
// 遍历表头数组
header.forEach(zhKey => {
  // 通过中文key找到英文key
  const enKey = headerRalation[zhKey]
  arr.push(obj1[enKey])
})
// console.log(arr)

// const arr = [1,2,3,4]
// this.arr[0] = 99
// this.$set(this.arr, 0, 99)

// RBAC页面/路由的访问权的核心实现思路：
// RBAC: 基于角色的权限控制，核心思想是给员工分配角色，给角色分配权限，
//       实现不用员工登录成功看到的左侧菜单不同(权限不同)
// 1. 主页的左侧菜单是基于路由表动态生成的(控制左侧菜单的不同只需要控制路由表即可)
// 2. 路由表划分为静态路由表和动态路由表，控制权限的不同就是在控制动态路由表
// 3. 在路由全局全局守卫中，基于请求到的用户菜单，对动态路由表做筛选(比对路由规则的名字是否在用户菜单数组中)
// 4. 把筛选的结果通过路由实例的addRoute方法动态追加到路由表中(浏览器输入path可以看到component)
// 5. vuex管理一份路由表，同步相应菜单的显示(因为router.options.routes不是响应式的)

// 按钮的操作权：
// （1）3种实现方式：
//      1. 是否渲染(v-if指令)
//      2. 是否禁用(: disabled属性)
//      3. 代码中的逻辑判断(有权限放行, 否则直接return)
// (2) 代码中
//   1. 自定义全局指令(v-permission)
//        判断指令绑定表达式的值是否在vuex中用户权限点的数组中
//   2. 给Vue新增原型方法($checkPermission)
//        判断方法参数值是否在vuex中用户权限点的数组中

// 人资项目必会面试题：
// 1. token为什么用vuex和本地存储共同管理？(只用本地存储管理行不行)
// 答：2者都有优缺点
//    vuex:
//       优点：1. 响应式  2. 读写速度快(从内存中读写)    缺点：刷新会丢失（数据不会持久化）
//    本地存储/Cookie:
//       优点：刷新不丢失（数据会持久化）    缺点：1. 非响应式  2. 读取速度慢(从磁盘中读写)

// 2. token拦截/登录拦截/路由访问权限 如何实现？
// 答：1. 借助router.beforeEach((to, from, next) => { })路由全局前置守卫，
//        因为任何路由在被访问到之前必须经过回调函数的处理
//    2. 在回调中获取vuex中的token，判断token是否存在
//    3. 如果存在，直接放行
//    3. 否则，进一步判断要去的路由路径是否在白名单数组中，如果在，放行；否则跳转至登录，携带回跳地址

// 3. token过期了有哪些处理方案？
// 答：1. 在项目做过2中方式的token过期处理，分别是无感知的处理和有感知的处理
//    2. 无感知的处理也可以称为token的续签，在首次登录成功之后，后台会给到2个token信息，
//       一个叫token，另一个叫refreshToken，并且refreshToken的有效期比token长，当token过期了，
//       并不代表refreshToken也过期了，这个时候可以在响应拦截器中监测401状态码，用refreshToken请求
//       得到新token，然后把新token同步到vuex中，然后继续刚刚失败的请求
//    3. 有感知的处理就是2个token都过期了，清空token和用户信息，然后重新登陆；
//       或者在首次登录成功后台就只给了一个token，token过期了，同样的在响应拦截器中监测401状态码，然后重新登陆

// 4. 数据转换？
// 答：
//    1. 数组转树：
//       （1）在组织架构模块，后台给到的是列表(数组)数据，需要转换成树形结构，通过层级关系来渲染
//       （2）核心转换思路：
//             （1）自定义转换函数，首先查找一级部门，把找到的一级部门存入结果数组
//             （2）查找一级部门下是否存在子级部门，查找到的条件就是哪个部门的pid与当期那部门的id全等
//                 通过函数递归，得到子级部门，把得到子级children数组添加给一级部门的children属性

//    2. Excel的上传与下载
//     上传：
//        本质：把Excel文件中数据读到内存中，得到一个对象数组，
//        问题：但是每个对象中的键是中文的，需要转换成英文键，提交给后台
//        转换的核心思路：
//         1. 基于数组的map，自定义中英文键的映射关系对象，
//         2. 遍历对象，通过英文键得到中文键，再赋值给新对象即可
//     下载：
//        本质：把内存中对象数组写入Excel文件的过程
//        问题：后台给到的对象数组，写入到Excel中文中的数据是个二维数组
//        转换的核心思路：
//         1. 基于数组的map，自定义中英文键的映射关系对象，
//         2. 遍历表头数组，通过英文键得到中文键，再加入到新数组中

// 4. 项目中封装过哪些组件？封装组件的核心思路？
// 封装过哪些组件：封装过图片上传组件、页头组件、全屏组件等
// 核心思路(高内聚低耦合)：大致关注4个点
//  高内聚：组件内部把某个点的功能涵盖的很全面(功能强大)
//  低耦合：尽量保持组件的独立性(尽量不依赖其它组件，能够独立工作)
// 1. props: 父传子，使用组件的时候，通过自定义属性控制组件的外观/行为
// 2. slot: 插槽, 使用组件的时候，允许自定义标签结构分发内容
// 3. events: 事件，通过动作记录组件的行为
// 4. methods: 组件的方法

